import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Graphics;
import javax.microedition.sensor.Data;
import javax.microedition.sensor.DataListener;
import javax.microedition.sensor.SensorConnection;
import javax.microedition.sensor.SensorInfo;
import javax.microedition.sensor.SensorManager;
import java.io.IOException;
import javax.microedition.io.Connector;
import java.lang.Math;
import java.lang.System;
import javax.microedition.lcdui.*;
import javax.microedition.io.file.*;
import javax.microedition.io.*;
import java.io.*;
import javax.microedition.midlet.*;
import java.util.Date;
import java.util.Calendar;


 

public class SensorCanvas extends Canvas implements CommandListener, DataListener, Runnable {
    private SensorTest midlet;
    private int width, height;                  // Screen width and height
    private int d, r;                           // Radius and diameter of the ball
    private int x_int, y_int, z_int;            // Sensor directions as integers x_int, y_int and z_int
    private double x, y, z;                     // Sensor directions as doubles x, y and z
    protected int xcoord, ycoord;               // Upper-left corner of the drawn ball
    private Command startIntCommand;            // Search and use TYPE_INT accelerometer
    private Command startDoubleCommand;         // Search and use TYPE_DOUBLE accelerometer
    private Command stopCommand;
    private Command exitCommand;
    private Command startIntBezZ;
    private Command startDoubleBezZ;
    private static SensorConnection sensor = null;
    private SensorInfo infos[];                 // SensorInfo objects containing info about sensors
    private static boolean isStopped = false;   // Is sensor thread running?
    private static boolean type_int = true;     // Are we using integer type sensor?
    private static boolean czy_zapis = true;
    private static boolean sensor_found = false;// Have we found the correct sensor?
    private static final int BUFFER_SIZE = 1;   // Buffer for the sensor data
    private Thread thread = null;               // Thread for initializing and listening sensor
    
    private long czasPocz = 0;
    private long czasUplynal;
    private String photons = "fileconn.dir.memorycard";
    private String path = System.getProperty(photons) + "Aaa/"; // mo?na zapisywa? na karciosze pami?ciochy. Rozw. prowizoryczne
    private int licznik_dozapisu = 0;
    private String dane = "";
    
    private FileConnection fconn;
    
    private byte [] spacja, nowaLinia;
    int[][] tablica = new int[1000][4]; 
    
    


    public SensorCanvas(SensorTest midlet) {
        this.setFullScreenMode(true);
        this.midlet = midlet;
        x = 0;
        y = 0;
        z = 0;
        r = 5;
        d = 2*r;
        width = getWidth();
        height = getHeight();
        xcoord = width/2 - r;
        ycoord = height/2 - r;
        startIntCommand = new Command("Start (Int)", Command.SCREEN, 1);
//        startDoubleCommand = new Command("Start (Double)", Command.SCREEN, 1);
        stopCommand = new Command("Stop", Command.STOP, 1);
        exitCommand = new Command("Wyjscie", Command.EXIT, 1);
        startIntBezZ = new Command("Start (Int) bez zapisu", Command.SCREEN, 1);
//        startDoubleBezZ = new Command("Start (Double) bez zapisu", Command.SCREEN, 1);
        this.addCommand(startIntCommand);
//        this.addCommand(startDoubleCommand);
        this.addCommand(startIntBezZ);
//        this.addCommand(startDoubleBezZ);
        this.addCommand(exitCommand);
        this.setCommandListener(this);
        try
        {
            Calendar kalendarz = Calendar.getInstance();
            int rok = kalendarz.get(Calendar.YEAR);
            int miesiac = kalendarz.get(Calendar.MONTH);
            int dzien = kalendarz.get(Calendar.DAY_OF_MONTH);
            int godzina = kalendarz.get(Calendar.HOUR_OF_DAY);
            int minuta = kalendarz.get(Calendar.MINUTE);
            int sekunda = kalendarz.get(Calendar.SECOND);
            String url = path + rok + "-" + miesiac + "-" + dzien + " " + godzina + "-" + minuta + "-" + sekunda; //zmiana nazwy pliku na czytelniejsz?
            byte[] bytes = dane.getBytes("UTF-8");
            fconn = (FileConnection)Connector.open(url, Connector.READ_WRITE);
            if (!fconn.exists())
            {
                fconn.create();
            }
        }
        catch (IOException ioe)
        {
            System.out.println("IOException: "+ioe.getMessage());
        }
        catch (SecurityException se)
        {
            System.out.println("Security exception:" + se.getMessage());
        }
        try {
           spacja = " ".getBytes("UTF-8");
        }
        catch (UnsupportedEncodingException ex) {
           // ex.printStackTrace();
        }
        try {
           nowaLinia = "\n".getBytes("UTF-8");
        }
        catch (UnsupportedEncodingException ex) {
           // ex.printStackTrace();
        }
        
    }

    /**
     * Initializes (opens) the sensor and sets the DataListener
     */
    private synchronized void initSensor() {
        sensor = openSensor();
        if (sensor == null) return;
        try
        {
            sensor.setDataListener(this, BUFFER_SIZE);
            while(!isStopped)
            {
                try
                {
                    wait();
                }
                catch(InterruptedException ie){}
            }
            sensor.removeDataListener();
        }
        catch (IllegalMonitorStateException imse)
        {
            imse.printStackTrace();
        }
        catch (IllegalArgumentException iae)
        {
            iae.printStackTrace();
        }
        try 
        {
            sensor.close();
        }
        catch(IOException ioe)
        {
            ioe.printStackTrace();
        }
        if (isStopped)
        {
            sensor = null;
        }
    }

    /**
     * Searches sensors of "accelerator" quantity and if found returns a 
     * SensorConnection opened to it. Based on the boolean value of type_int
     * either TYPE_DOUBLE or TYPE_INT sensor is used.
     * @return SensorConnection, which has been opened to a sensor matching the criteria
     */
    private SensorConnection openSensor() {
        infos = SensorManager.findSensors("acceleration", null);
        if (infos.length==0) return null;
        int datatypes[] = new int[infos.length];
        int i = 0;
        String sensor_url = "";
        if (!type_int) {
            System.out.println("Searching TYPE_DOUBLE sensor...");
            while (!sensor_found) {
                datatypes[i] = infos[i].getChannelInfos()[0].getDataType();
                if (datatypes[i] == 1) { //ChannelType.TYPE_DOUBLE = 1
                    sensor_url = infos[i].getUrl();
                    System.out.println("Sensor: " + sensor_url + ": TYPE_DOUBLE found.");
                    sensor_found = true;
                }
                else i++;
            }
        }
        else if (type_int) {
            System.out.println("Searching TYPE_INT sensor...");
            while (!sensor_found) {
                datatypes[i] = infos[i].getChannelInfos()[0].getDataType();
                if (datatypes[i] == 2) { //ChannelType.TYPE_INT = 2
                    sensor_url = infos[i].getUrl();
                    System.out.println("Sensor: " + sensor_url + ": TYPE_INT found.");
                    sensor_found = true;
                }
                else i++;
            }
        }
        System.out.println("Sensor: " + sensor_url);
        try {
            return (SensorConnection)Connector.open(sensor_url);
        }
        catch (IOException ioe) {
            ioe.printStackTrace();
            return null;
        }
    }

    
    public void paint(Graphics g) {
        
        
        int size = 10;
        
        width = getWidth();
        height = getHeight();
        g.setColor(255, 255, 255);
        g.fillRect(0, 0, width, height);
        g.setColor(255, 0, 0);
        g.drawRect(0, 0, width - 1, height - 1);
        g.setColor(0, 0, 0);
        g.fillArc(xcoord, ycoord, d, d, 0, 360);
        g.setColor(0, 255, 0);
        g.drawLine(0, height/2, width, height/2);
        g.drawLine(width/2, 0, width/2, height);
        g.setColor(0, 0, 0);
        if (czy_zapis)
        {
            if (licznik_dozapisu == 999)
            {
//                for (int i = 0; i < 1000; i++){
//                    for (int j = 0; j < 4; j++){
//                        dane += tablica[i][j];
//                    }
//                }
////                dane = riplejs (dane, ".", ",");
//                saveFile(dane);
               //
                zapiszPlik(tablica);
//                dane = "";
            }
//            g.drawString("co pisane = " + toBytes(tablica[licznik_dozapisu- 1][0]), 0, 40, Graphics.TOP|Graphics.LEFT);
            g.drawString("licznik = " + licznik_dozapisu, 0, 60, Graphics.TOP|Graphics.LEFT);
            g.drawString("czas = " + tablica[licznik_dozapisu - 1][3], 0, 80, Graphics.TOP|Graphics.LEFT);
//            Thread t = Thread.currentThread();
//                String name = t.getName();
//                g.drawString(name, 0, 80, Graphics.TOP|Graphics.LEFT); 

            try
            {
                g.drawString("dlugosc pliku = " + (fconn.fileSize()), 0, 20, Graphics.TOP|Graphics.LEFT);
            }
            catch (IOException ioe)
            {
                System.out.println("IOException: "+ioe.getMessage());
            }
            catch (SecurityException se)
            {
                System.out.println("Security exception:" + se.getMessage());
            }
        }
        else
        {
//            if (!type_int) {
//            x_int = (int)(x*10);
//            y_int = (int)(y*10);
//            z_int = (int)(z*10);
//            g.drawString("x = " + x, 0, 20, Graphics.TOP|Graphics.LEFT);
//            g.drawString("y = " + y, 0, 40, Graphics.TOP|Graphics.LEFT);
//            g.drawString("z = " + z, 0, 60, Graphics.TOP|Graphics.LEFT);
//            }
//            else 
    if (type_int) {
                g.drawString("INT x = " + tablica[licznik_dozapisu - 1][0], 0, 20, Graphics.TOP|Graphics.LEFT);
                g.drawString("INT y = " + y_int, 0, 40, Graphics.TOP|Graphics.LEFT);
                g.drawString("czas = " + tablica[licznik_dozapisu - 1][3], 0, 60, Graphics.TOP|Graphics.LEFT); //
                
            }
            if (z_int < 0) {
                g.setColor(255, 0, 0);  // Red
                int diameter = z_int;
                g.drawArc(width/2-diameter/2, height/2-diameter/2, diameter, diameter, 0, 360);
            }
            else if (z_int > 0) {
                g.setColor(0, 0, 255);  // Blue
                int diameter = z_int;
                g.drawArc(width/2-diameter/2, height/2-diameter/2, diameter, diameter, 0, 360);
            }
            if (x_int < 0) {
                for (int i = x_int; i < 0; i = i+10) {
                    g.setColor(255, Math.abs(i), 0); // Red <-> Yellow
                    g.fillArc(xcoord + i, ycoord, size, size, 0, 360);
                }
            }
            else if (x_int > 0) {
                for (int i = 0; i < x_int; i = i+10) {
                    g.setColor(255, i, 0); // Red <-> Yellow
                    g.fillArc(xcoord + i, ycoord, size, size, 0, 360);
                }
            }
            if (y_int < 0) {
                for (int i = y_int; i < 0; i = i+10) {
                    g.setColor(255, Math.abs(i), 0); // Red <-> Yellow
                    g.fillArc(xcoord, ycoord - i, size, size, 0, 360);
                }
            }
            else if (y_int > 0) {
                for (int i = 0; i < y_int; i = i+10) {
                    g.setColor(255, i, 0); // Red <-> Yellow
                    g.fillArc(xcoord, ycoord - i, size, size, 0, 360);
                }
            }
        }

    }

    protected void sizeChanged(int w, int h) {
        xcoord = w/2 - r;
        ycoord = h/2 - r;
    }
    
    protected  void keyPressed(int keyCode) { }
    
    protected  void keyReleased(int keyCode) { }

    protected  void keyRepeated(int keyCode) { }
    
    protected  void pointerDragged(int x, int y) { }

    protected  void pointerPressed(int x, int y) { }

    protected  void pointerReleased(int x, int y) { }
    
    public void commandAction(Command c, Displayable d) {
        if (c == startIntCommand) {
            type_int = true;
            czy_zapis = true;
            this.addCommand(stopCommand);
            this.removeCommand(startIntCommand);
            this.removeCommand(startDoubleCommand);
            this.removeCommand(startDoubleBezZ);
            this.removeCommand(startIntBezZ);
            start();
        }
//        if (c == startDoubleCommand)
//        {
//            type_int = false;
//            czy_zapis = true;
//            this.addCommand(stopCommand);
//            this.removeCommand(startIntCommand);
//            this.removeCommand(startDoubleCommand);
//            this.removeCommand(startDoubleBezZ);
//            this.removeCommand(startIntBezZ);
//            start();
//        }
        
        if (c == startIntBezZ)
        {
            type_int = true;
            czy_zapis = false;
            this.addCommand(stopCommand);
            this.removeCommand(startIntCommand);
            this.removeCommand(startDoubleCommand);
            this.removeCommand(startDoubleBezZ);
            this.removeCommand(startIntBezZ);
            start();
        }
        
//        if (c == startDoubleBezZ)
//        {
//            type_int = false;
//            czy_zapis = false;
//            this.addCommand(stopCommand);
//            this.removeCommand(startIntCommand);
//            this.removeCommand(startDoubleCommand);
//            this.removeCommand(startDoubleBezZ);
//            this.removeCommand(startIntBezZ);
//            start();
//        }
        
        if (c == stopCommand) {
            stop();
            sensor_found = false;
            this.addCommand(startIntCommand);
//            this.addCommand(startDoubleCommand);
//            this.addCommand(startDoubleBezZ);
            this.addCommand(startIntBezZ);
            this.removeCommand(stopCommand);
            
        }
        if (c == exitCommand)
        {
            try
            {
                fconn.close();
            }
            catch (IOException ioe) {
                System.out.println("IOException: "+ioe.getMessage());
            }
            catch (SecurityException se) {
                System.out.println("Security exception:" + se.getMessage());
            }
            stop();
            midlet.notifyDestroyed();
        }
    }

     /**
     * Notification of the received sensor data.
     * @param sensor - SensorConnection, the origin of the received data
     * @param data - the received sensor data
     * @param isDataLost - true if some data has been lost 
     * 
     * W metodzie znajduje si? kod odpowiedzialny za zapisywanie do pliku (przeniesiony tu z metody rysuj?cej)
     */
    public void dataReceived(SensorConnection sensor, Data[] data, boolean isDataLost)
    {
        
//        if (!type_int) {
//            double[] directions = getDirections(data);
//            x = directions[0];
//            y = directions[1];
//            z = directions[2]; 
////            l_baPomiarow++;
//            if(czy_zapis)
//            {
//                dane += Long.toString(czasUplynal) + " " + Double.toString((double)(int)((x+0.0005)*1000.0)/1000.0)  + " " + Double.toString((double)(int)((y+0.0005)*1000.0)/1000.0)  + " " + Double.toString((double)(int)((z+0.0005)*1000.0)/1000.0) + "\n";
//                licznik_dozapisu++;
//                licznik_dozapisu = licznik_dozapisu%250;
//                if (licznik_dozapisu == 0)
//                {
//                  //  dane = riplejs (dane, ".", ",");
//                }
//            }
////            dane = riplejs (dane, ".", ",");

//    
//        }
//        else {
            int[] directions = getIntegerDirections(data);
            czasUplynal = System.currentTimeMillis() - czasPocz;
            czasPocz = System.currentTimeMillis();
            
//            tablica[licznik_dozapisu][3] = directions[3];
            x_int = directions[0];
            y_int = directions[1];
            z_int = directions[2];
            
            tablica[licznik_dozapisu][0] = x_int;
            tablica[licznik_dozapisu][1] = y_int;
            tablica[licznik_dozapisu][2] = z_int;
            tablica[licznik_dozapisu][3] = (int)czasUplynal;
            
//            if (czy_zapis)
//            {
//                dane += Long.toString(czasUplynal) + " " + x_int  + " " + y_int  + " " + z_int + "\n";
                
                licznik_dozapisu++;
                licznik_dozapisu = licznik_dozapisu%1000;
//            }
//        }
        repaint();
//        if (czy_zapis) 
//        {
//            if (licznik_dozapisu == 0)
//            {
////                repaint();
//            }
//        }
//        else
//        {
//            repaint();
//        }
    }
        
        
    
    
    

    /**
     * Gets the directions (axis_x, axis_y and axis_z values) from the accelerator
     * sensor data. An average value is calculated from the buffer values.
     * @param data The sensor data
     * @return directions The array containing the axis_x, axis_y and axis_z values
     */
	private int[] getIntegerDirections(Data[] data)  // usun??em statyczno?? metody
        {
            int [][] intValues = new int[3][BUFFER_SIZE];
            int[] directions = new int[3];
            for (int i=0; i<3; i++)
            {
                intValues[i] = data[i].getIntValues();
                int temp = 0;
                for (int j = 0; j<BUFFER_SIZE; j++)
                {
                    temp = temp + intValues[i][j];
                }
                directions[i] = temp/BUFFER_SIZE;
            }
//            czasUplynal = System.currentTimeMillis() - czasPocz;
//            czasPocz = System.currentTimeMillis();
//            directions[4] = (int)czasUplynal;
            
            return directions;
	}
        
    
    /**
     * Gets the directions (axis_x, axis_y and axis_z values) from the accelerator
     * sensor data. An average value is calculated from the buffer values.
     * @param data The sensor data
     * @return directions The array containing the axis_x, axis_y and axis_z values
     */
	private static double[] getDirections(Data[] data) {
		double[][] doubleValues = new double[3][BUFFER_SIZE];
        double[] directions = new double[3];
		for (int i=0; i<3; i++){
			doubleValues[i] = data[i].getDoubleValues();
            double temp = 0;
            for (int j = 0; j<BUFFER_SIZE; j++) {
                temp = temp + doubleValues[i][j];
            }
            directions[i] = temp/BUFFER_SIZE;
//            long czas = data[i].getTimestamp(i);
		}
		return directions;
	}

	private synchronized void setStopped(boolean stopped){
//		licznik_dozapisu = 0;        
//                saveFile(dane);
//                dane = "";
//           by? mo?e tych pare linijek powodowalo, ze nie mozna bylo zamknac regularnie aplikacji
        
                isStopped = stopped;
		notify();
        if (thread != null) thread = null;
	}

    synchronized void start() {
        setStopped(false);
        if (thread == null) thread = new Thread(this);
        thread.start();
    }

    synchronized void stop() {
        setStopped(true);
        thread = null;
        
    }

    public void run() {
        initSensor();
    }
    
    
    /* Metoda prowizoryczna do zamiany kropek dzies. na przecinki - moze nie bedzie potrzebna
     * 
     */
   public static String riplejs (String _text, String _searchStr, String _replacementStr)
   {
       StringBuffer sb = new StringBuffer ();
       int searchStringPos = _text.indexOf(_searchStr);
       int startPos = 0;
       int searchStringLength = _searchStr.length();
       while (searchStringPos != -1)
       {
           sb.append(_text.substring(startPos, searchStringPos)).append(_replacementStr);
           startPos = searchStringPos + searchStringLength;
           searchStringPos = _text.indexOf(_searchStr, startPos);
       }
       sb.append(_text.substring(startPos, _text.length()));
       return sb.toString();
   }
    /*
    * Metoda prowizoryczna do zapisu do pliku
    */
    //private void saveFile(String path, String name, String dane) {
    private void saveFile(String dane) {
        try {
         //   String url = path + name;
            //String string = textbox.getString();
            byte[] bytes = dane.getBytes("UTF-8");
            //FileConnection fconn = (FileConnection)Connector.open(url, Connector.READ_WRITE);
            //if (!fconn.exists()) {
           //     fconn.create();
           // }
            //fconn.truncate(fconn.usedSize());
            OutputStream ops = fconn.openOutputStream(fconn.fileSize());
            
            ops.write(bytes);
            ops.close();
            
            //fconn.close();
        }
        catch (IOException ioe) {
            System.out.println("IOException: "+ioe.getMessage());
        }
        catch (SecurityException se) {
            System.out.println("Security exception:" + se.getMessage());
        }
    } 
    

    private void zapiszPlik (int [][] dane) // nowa lepsiejsza chyba metoda do zapisu
    {
        byte [] bajt = new byte [4];
        int calkowita;
        try {
            OutputStream ops = fconn.openOutputStream(fconn.fileSize());
            for(int i=0; i<1000; i++){
                for (int j=0; j<4; j++){
                    calkowita = dane[i][j];
                    bajt = toBytes(calkowita);
                    ops.write(bajt);
//                    ops.write((byte) (dane[i][j] >> 24));
//                    ops.write((byte) (dane[i][j] >> 16));
//                    ops.write((byte) (dane[i][j] >> 8));
//                    ops.write((byte) (dane[i][j]));
                    ops.write(spacja); //opcjonalne, je?li b?dzie za wolno to si? z tego wycofam
                }
                ops.write(nowaLinia); //opcjonalne, je?li b?dzie za wolno to si? z tego wycofam
            }
//            System.out.println("hej dupa dupa");
            ops.close();
        }
        catch (IOException ioe) {
            System.out.println("IOException: "+ioe.getMessage());
        }
        catch (SecurityException se) {
            System.out.println("Security exception:" + se.getMessage());
        }
    }
    
    private byte[] toBytes(int i)
    {
        byte[] result = new byte[4];

        result[0] = (byte) (i >> 24);
        result[1] = (byte) (i >> 16);
        result[2] = (byte) (i >> 8);
        result[3] = (byte) (i /*>> 0*/);

        return result;
    }
}